package server

import (
	"context"
	"flag"
	"os"
	"os/signal"
	"pay/pkg/log"
	"sync"
	"syscall"
)

// 全局配置文件对象
type Conf interface {
	// 初始化配置信息
	Init(ctx context.Context) error
}

// 全局service调度对象
type Server interface {
	// 初始化服务配置&服务执行器
	Init(ctx context.Context) error
	// 启动block服务和关联goroutine
	StartServer() error
	// 服务关闭
	Close(ctx context.Context)
}

func Run(conf Conf, server Server) {
	flag.Parse()
	ctx, closer := initServerContextWithSignal(server, syscall.SIGINT, syscall.SIGTERM)
	defer gracefulCloser(ctx, server, closer)
	if err := initService(ctx, conf, server); err != nil {
		log.FromContext(ctx).Warn(err)
	}
}

func initService(ctx context.Context, conf Conf, server Server) error {
	// 读取配置文件
	if err := conf.Init(ctx); err != nil {
		return err
	}
	// 初始化Server
	if err := server.Init(ctx); err != nil {
		return err
	}
	// 启动服务
	if err := server.StartServer(); err != nil {
		return err
	}
	return nil
}

var once sync.Once

func gracefulCloser(ctx context.Context, server Server, ctxCancel context.CancelFunc) {
	// 由于中断 & defer均可触发，这里只允许执行一次
	if r := recover(); r != nil {
		log.FromContext(ctx).Errorf("server panic: %+v", r)
	}
	once.Do(func() {
		server.Close(ctx)
		ctxCancel()
		os.Exit(1)
	})
}

func initServerContextWithSignal(server Server, signals ...os.Signal) (context.Context, func()) {
	ctx, closer := context.WithCancel(context.Background())
	c := make(chan os.Signal, 1)
	signal.Notify(c, signals...)
	go func() {
		select {
		case <-c:
			log.FromContext(ctx).Warnf("收到信号: %s", <-c)
			gracefulCloser(ctx, server, closer)
		case <-ctx.Done():
		}
	}()
	return ctx, closer
}
